package socket

import (
	"errors"
	socketio "github.com/googollee/go-socket.io"
	"sync"
)

type IoClient struct {
	Conn socketio.Conn
	Uid  int64
}

var Manager *IoHub
var StoreSocketIo = new(IOStore)

func init() {
	Manager = newIoHub()
}

func newIoHub() *IoHub {
	StoreSocketIo.cli = make(map[string]IoClient)
	return &IoHub{
		Register:   make(chan IoClient),
		Unregister: make(chan string),
		//Clients:      make(map[string]*IoClient),
		UserClient:   make(map[int64]IoClient),
		UidBroadcast: make(chan map[int64]SocketMsg),
	}
}

type SocketMsg struct {
	Event string
	Msg   interface{}
}

type IoHub struct {
	Register     chan IoClient
	Unregister   chan string
	UserClient   map[int64]IoClient // key 用户ID value soketIo链接
	UidBroadcast chan map[int64]SocketMsg
}

// Start 启动websocket服务.
func (h *IoHub) Start() {
	for {
		select {
		case conn := <-h.Register:
			StoreSocketIo.Set(conn.Conn.ID(), conn)
			h.UserClient[conn.Uid] = conn
		case ID := <-h.Unregister:
			if StoreSocketIo.IsExist(ID) {
				value, err := StoreSocketIo.Get(ID)
				if err == nil {
					// 移除 UserClient
					if _, o := h.UserClient[value.Uid]; o {
						delete(h.UserClient, value.Uid)
					}
					StoreSocketIo.Remove(ID)
					// 离开所有的房间.
					IoRoom.ExitAllRoom(value.Uid)
				}
			}
		case pushMsg := <-h.UidBroadcast:
			for id, value := range pushMsg {
				if v, ok := h.UserClient[id]; ok {
					v.Conn.Emit(value.Event, value.Msg)
				}
			}
		}
	}
}

// IOStore 存储了socketIo 的 id 和 链接.
type IOStore struct {
	rw  sync.RWMutex
	cli map[string]IoClient // key 链接ID
}

// Get 获取用户ID.
func (io *IOStore) Get(ID string) (IoClient, error) {
	io.rw.RLock()
	defer io.rw.RUnlock()
	if v, ok := io.cli[ID]; ok {
		return v, nil
	}
	return IoClient{}, errors.New("not found")
}

// Set 获取用户ID.
func (io *IOStore) Set(ID string, ioClient IoClient) {
	io.rw.Lock()
	defer io.rw.Unlock()
	io.cli[ID] = ioClient
}

// Remove 移除.
func (io *IOStore) Remove(ID string) bool {
	io.rw.Lock()
	defer io.rw.Unlock()
	if _, ok := io.cli[ID]; ok {
		delete(io.cli, ID)
		return true
	}
	return false
}

// IsExist 是否存在.
func (io *IOStore) IsExist(ID string) bool {
	io.rw.RLock()
	defer io.rw.RUnlock()
	if _, ok := io.cli[ID]; ok {
		return true
	}
	return false
}
